/// {{{operationId}}} - {{{httpMethod}}} {{{basePathWithoutHost}}}{{{path}}}
#[tracing::instrument(skip_all)]
async fn {{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}<I, A, E{{#havingAuthMethod}}, C{{/havingAuthMethod}}>(
  method: Method,
  host: Host,
  cookies: CookieJar,
{{#headerParams.size}}
  headers: HeaderMap,
{{/headerParams.size}}
{{^headerParams.size}}
{{#vendorExtensions}}
{{#x-has-header-auth-methods}}
  headers: HeaderMap,
{{/x-has-header-auth-methods}}
{{^x-has-header-auth-methods}}
  {{#x-has-basic-auth-methods}}
  headers: HeaderMap,
  {{/x-has-basic-auth-methods}}
{{/x-has-header-auth-methods}}
{{/vendorExtensions}}
{{/headerParams.size}}
{{#pathParams.size}}
  Path(path_params): Path<models::{{{operationIdCamelCase}}}PathParams>,
{{/pathParams.size}}
{{#queryParams.size}}
  QueryExtra(query_params): QueryExtra<models::{{{operationIdCamelCase}}}QueryParams>,
{{/queryParams.size}}
 State(api_impl): State<I>,
{{#vendorExtensions}}
{{^x-consumes-multipart-related}}
{{^x-consumes-multipart}}
  {{#bodyParam}}
    {{#vendorExtensions}}
      {{#x-consumes-json}}
          Json(body): Json<{{^required}}Option<{{/required}}{{{dataType}}}{{^required}}>{{/required}}>,
      {{/x-consumes-json}}
      {{#x-consumes-form-urlencoded}}
          Form(body): Form<{{^required}}Option<{{/required}}{{{dataType}}}{{^required}}>{{/required}}>,
      {{/x-consumes-form-urlencoded}}
      {{#x-consumes-plain-text}}
        {{#isString}}
          body: String,
        {{/isString}}
        {{^isString}}
          body: Bytes,
        {{/isString}}
      {{/x-consumes-plain-text}}
    {{/vendorExtensions}}
  {{/bodyParam}}
{{/x-consumes-multipart}}
{{/x-consumes-multipart-related}}
{{#x-consumes-multipart}}
  body: Multipart,
{{/x-consumes-multipart}}
{{#x-consumes-multipart-related}}
  body: axum::body::Body,
{{/x-consumes-multipart-related}}
{{/vendorExtensions}}
) -> Result<Response, StatusCode>
where
    I: AsRef<A> + Send + Sync,
    A: {{#basicAnalytic}}apis::EventDispatcher + {{/basicAnalytic}}apis::{{classFilename}}::{{classnamePascalCase}}<E{{#havingAuthMethod}}, Claims = C{{/havingAuthMethod}}>{{#havingAuthMethod}}{{#basicAuthorization}} + apis::{{classFilename}}::{{classnamePascalCase}}Authorization<Claims = C>{{/basicAuthorization}}{{/havingAuthMethod}}{{#vendorExtensions}}{{#x-has-cookie-auth-methods}}+ apis::CookieAuthentication<Claims = C>{{/x-has-cookie-auth-methods}}{{#x-has-header-auth-methods}}+ apis::ApiKeyAuthHeader<Claims = C>{{/x-has-header-auth-methods}}{{#x-has-basic-auth-methods}}+ apis::ApiAuthBasic<Claims = C>{{/x-has-basic-auth-methods}}{{/vendorExtensions}} + Send + Sync,
    E: std::fmt::Debug + Send + Sync + 'static,
        {
{{#basicAnalytic}}let start_at = chrono::Utc::now();{{/basicAnalytic}}

{{#vendorExtensions}}
{{#x-has-auth-methods}}
    // Authentication
{{/x-has-auth-methods}}
{{#x-has-cookie-auth-methods}}
    let claims_in_cookie = api_impl.as_ref().extract_claims_from_cookie(&cookies, "{{x-api-key-cookie-name}}").await;
{{/x-has-cookie-auth-methods}}
{{#x-has-header-auth-methods}}
    let claims_in_header = api_impl.as_ref().extract_claims_from_header(&headers, "{{x-api-key-header-name}}").await;
{{/x-has-header-auth-methods}}
{{#x-has-basic-auth-methods}}
    let claims_in_auth_header = api_impl.as_ref().extract_claims_from_auth_header(apis::BasicAuthKind::{{#x-is-basic-bearer}}Bearer{{/x-is-basic-bearer}}{{^x-is-basic-bearer}}Basic{{/x-is-basic-bearer}}, &headers, "{{x-api-auth-header-name}}").await;
{{/x-has-basic-auth-methods}}
{{#x-has-auth-methods}}
    let claims = None
          {{#x-has-cookie-auth-methods}}
             .or(claims_in_cookie)
          {{/x-has-cookie-auth-methods}}
          {{#x-has-header-auth-methods}}
              .or(claims_in_header)
          {{/x-has-header-auth-methods}}
          {{#x-has-basic-auth-methods}}
             .or(claims_in_auth_header)
          {{/x-has-basic-auth-methods}}
          ;
    let Some(claims) = claims else {
        return response_with_status_code_only(StatusCode::UNAUTHORIZED);
    };
{{/x-has-auth-methods}}
{{/vendorExtensions}}

{{#headerParams}}
  {{#-first}}
    // Header parameters
    let header_params = {
  {{/-first}}
                let header_{{{paramName}}} = headers.get(HeaderName::from_static("{{{nameInLowerCase}}}"));

                let header_{{{paramName}}} = match header_{{{paramName}}} {
                    Some(v) => match header::IntoHeaderValue::<{{{dataType}}}>::try_from((*v).clone()) {
                        Ok(result) =>
{{#required}}
                            result.0,
{{/required}}
{{^required}}
                            Some(result.0),
{{/required}}
                        Err(err) => {
                            return Response::builder()
                                        .status(StatusCode::BAD_REQUEST)
                                        .body(Body::from(format!("Invalid header {{{baseName}}} - {err}"))).map_err(|e| { error!(error = ?e); StatusCode::INTERNAL_SERVER_ERROR });

                        },
                    },
                    None => {
{{#required}}
                        return Response::builder()
                                        .status(StatusCode::BAD_REQUEST)
                                        .body(Body::from("Missing required header {{{baseName}}}")).map_err(|e| { error!(error = ?e); StatusCode::INTERNAL_SERVER_ERROR });
{{/required}}
{{^required}}
                        None
{{/required}}
                    }
                };
{{/headerParams}}
{{#headerParams}}
  {{#-first}}

       models::{{{operationIdCamelCase}}}HeaderParams {
  {{/-first}}
          {{{paramName}}}: header_{{{paramName}}},
  {{#-last}}
       }
  };

  {{/-last}}
{{/headerParams}}

  {{^disableValidator}}
    {{^allowBlockingValidator}}
      #[allow(clippy::redundant_closure)]
      let validation = tokio::task::spawn_blocking(move ||
    {{/allowBlockingValidator}}
    {{#allowBlockingValidator}}
      let validation =
    {{/allowBlockingValidator}}
    {{#vendorExtensions}}{{{x-operation-id}}}_validation{{/vendorExtensions}}(
      {{#headerParams.size}}
        header_params,
      {{/headerParams.size}}
      {{#pathParams.size}}
        path_params,
      {{/pathParams.size}}
      {{#queryParams.size}}
        query_params,
      {{/queryParams.size}}
      {{^x-consumes-multipart-related}}
      {{^x-consumes-multipart}}
        {{#bodyParam}}
          body,
        {{/bodyParam}}
      {{/x-consumes-multipart}}
      {{/x-consumes-multipart-related}}
    )
  {{^allowBlockingValidator}}).await.unwrap(){{/allowBlockingValidator}};

  let Ok((
  {{#headerParams.size}}
    header_params,
  {{/headerParams.size}}
  {{#pathParams.size}}
    path_params,
  {{/pathParams.size}}
  {{#queryParams.size}}
    query_params,
  {{/queryParams.size}}
  {{^x-consumes-multipart-related}}
  {{^x-consumes-multipart}}
    {{#bodyParam}}
      body,
    {{/bodyParam}}
  {{/x-consumes-multipart}}
  {{/x-consumes-multipart-related}}
  )) = validation else {
    return Response::builder()
            .status(StatusCode::BAD_REQUEST)
            .body(Body::from(validation.unwrap_err().to_string()))
            .map_err(|_| StatusCode::BAD_REQUEST);
  };
  {{/disableValidator}}

{{#vendorExtensions}}
{{#x-has-auth-methods}}
  {{#basicAuthorization}}
    {{#vendorExtensions}}
      // Authorization
      let authorization = api_impl.as_ref().{{{x-operation-id}}}_authorize(
          &method,
          &host,
          &cookies,
          &claims,
          {{#headerParams.size}}
            &header_params,
          {{/headerParams.size}}
          {{#pathParams.size}}
            &path_params,
          {{/pathParams.size}}
          {{#queryParams.size}}
            &query_params,
          {{/queryParams.size}}
          {{#vendorExtensions}}
            {{^x-consumes-multipart-related}}
            {{^x-consumes-multipart}}
              {{#bodyParams}}
                {{#-first}}
                  &body,
                {{/-first}}
              {{/bodyParams}}
            {{/x-consumes-multipart}}
            {{/x-consumes-multipart-related}}
            {{#x-consumes-multipart}}
              &body,
            {{/x-consumes-multipart}}
            {{#x-consumes-multipart-related}}
              &body,
            {{/x-consumes-multipart-related}}
          {{/vendorExtensions}}
      ).await;
      match authorization {
          Ok(authorization) => match authorization {
              apis::Authorization::Authorized => {},
              apis::Authorization::Forbidden => { return response_with_status_code_only(StatusCode::FORBIDDEN); },
          },
          Err(_) => { return response_with_status_code_only(StatusCode::INTERNAL_SERVER_ERROR); }
      }
      {{/vendorExtensions}}
  {{/basicAuthorization}}
{{/x-has-auth-methods}}
{{/vendorExtensions}}

{{#basicAnalytic}}let mut event = apis::event::Event::default();{{/basicAnalytic}}
let result = api_impl.as_ref().{{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}(
      {{#basicAnalytic}}&mut event,{{/basicAnalytic}}
      {{^ownedRequest}}&{{/ownedRequest}}method,
      {{^ownedRequest}}&{{/ownedRequest}}host,
      {{^ownedRequest}}&{{/ownedRequest}}cookies,
      {{#vendorExtensions}}
        {{#x-has-auth-methods}}
        {{^ownedRequest}}&{{/ownedRequest}}claims,
        {{/x-has-auth-methods}}
      {{/vendorExtensions}}
      {{#headerParams.size}}
        {{^ownedRequest}}&{{/ownedRequest}}header_params,
      {{/headerParams.size}}
      {{#pathParams.size}}
        {{^ownedRequest}}&{{/ownedRequest}}path_params,
      {{/pathParams.size}}
      {{#queryParams.size}}
        {{^ownedRequest}}&{{/ownedRequest}}query_params,
      {{/queryParams.size}}
      {{#vendorExtensions}}
        {{^x-consumes-multipart-related}}
        {{^x-consumes-multipart}}
          {{#bodyParams}}
            {{#-first}}
              {{^ownedRequest}}&{{/ownedRequest}}body,
            {{/-first}}
          {{/bodyParams}}
        {{/x-consumes-multipart}}
        {{/x-consumes-multipart-related}}
        {{#x-consumes-multipart}}
          body,
        {{/x-consumes-multipart}}
        {{#x-consumes-multipart-related}}
          body,
        {{/x-consumes-multipart-related}}
      {{/vendorExtensions}}
  ).await;

  let mut response = Response::builder();

  let resp = match result {
                                            Ok(rsp) => match rsp {
{{#responses}}
                                                apis::{{classFilename}}::{{{operationId}}}Response::{{#vendorExtensions}}{{x-response-id}}{{/vendorExtensions}}
{{#dataType}}
{{^headers}}
                                                    (body)
{{/headers}}
{{#headers}}
{{#-first}}
                                                    {
                                                        body,
{{/-first}}
                                                        {{{name}}}{{^-last}},{{/-last}}
{{#-last}}
                                                    }
{{/-last}}
{{/headers}}
{{/dataType}}
{{^dataType}}
{{#headers}}
{{#-first}}
                                                    {
{{/-first}}
                                                        {{{name}}}{{^-last}},{{/-last}}
{{#-last}}
                                                    }
{{/-last}}
{{/headers}}
{{/dataType}}
                                                => {
{{#headers}}
  {{^required}}
                                                    if let Some({{{name}}}) = {{{name}}} {
  {{/required}}
                                                    let {{{name}}} = match header::IntoHeaderValue({{{name}}}).try_into() {
                                                        Ok(val) => val,
                                                        Err(e) => {
                                                            return Response::builder()
                                                                    .status(StatusCode::INTERNAL_SERVER_ERROR)
                                                                    .body(Body::from(format!("An internal server error occurred handling {{name}} header - {e}"))).map_err(|e| { error!(error = ?e); StatusCode::INTERNAL_SERVER_ERROR });
                                                        }
                                                    };


                                                    {
                                                      let mut response_headers = response.headers_mut().unwrap();
                                                      response_headers.insert(
                                                          HeaderName::from_static("{{{nameInLowerCase}}}"),
                                                          {{name}}
                                                      );
                                                    }
  {{^required}}
                                                    }
  {{/required}}
{{/headers}}
{{#range}}
                                                  response.status::<u16>(body.code.parse().unwrap());  // {{{code}}}
{{/range}}
{{^range}}
                                                  let mut response = response.status({{{code}}});
{{/range}}
{{#produces}}
{{#-first}}
{{#dataType}}
{{#vendorExtensions}}
                                                  {
                                                    let mut response_headers = response.headers_mut().unwrap();
                                                    response_headers.insert(
                                                        CONTENT_TYPE,
                                                        HeaderValue::from_static("{{{x-mime-type}}}"));
                                                  }

{{/vendorExtensions}}
{{/dataType}}
{{/-first}}
{{/produces}}
{{#dataType}}
{{#vendorExtensions}}
{{#x-produces-json}}
  {{^allowBlockingResponseSerialize}}
                                                  let body_content =  tokio::task::spawn_blocking(move ||
  {{/allowBlockingResponseSerialize}}
  {{#allowBlockingResponseSerialize}}
                                                  let body_content =
  {{/allowBlockingResponseSerialize}}
                                                      serde_json::to_vec(&body).map_err(|e| {
                                                        error!(error = ?e);
                                                        StatusCode::INTERNAL_SERVER_ERROR
                                                      }){{^allowBlockingResponseSerialize}}).await.unwrap(){{/allowBlockingResponseSerialize}}?;
{{/x-produces-json}}
{{#x-produces-form-urlencoded}}
  {{^allowBlockingResponseSerialize}}
                                                  let body_content =  tokio::task::spawn_blocking(move ||
  {{/allowBlockingResponseSerialize}}
  {{#allowBlockingResponseSerialize}}
                                                  let body_content =
  {{/allowBlockingResponseSerialize}}
                                                      serde_html_form::to_string(body).map_err(|e| {
                                                        error!(error = ?e);
                                                        StatusCode::INTERNAL_SERVER_ERROR
                                                      }){{^allowBlockingResponseSerialize}}).await.unwrap(){{/allowBlockingResponseSerialize}}?;
{{/x-produces-form-urlencoded}}
{{#x-produces-bytes}}
                                                  let body_content = body.0;
{{/x-produces-bytes}}
{{#x-produces-plain-text}}
                                                  let body_content = body;
{{/x-produces-plain-text}}
{{/vendorExtensions}}
                                                  response.body(Body::from(body_content))
{{/dataType}}
{{^dataType}}
                                                  response.body(Body::empty())
{{/dataType}}
                                                },
{{/responses}}
                                            },
                                            Err({{#ownedRequest}}_{{/ownedRequest}}why) => {
                                                {{^ownedRequest}}
                                                    // Application code returned an error. This should not happen, as the implementation should
                                                    // return a valid response.
                                                    return api_impl.as_ref().handle_error(&method, &host, &cookies, why).await;
                                                {{/ownedRequest}}
                                                {{#ownedRequest}}
                                                    return response_with_status_code_only(StatusCode::INTERNAL_SERVER_ERROR);
                                                {{/ownedRequest}}
                                            },
                                        };

                                        {{#basicAnalytic}}
                                        if let Ok(resp) = resp.as_ref() && !event.is_empty() {
                                             event.insert(apis::event::convention::EVENT_TIMESTAMP.to_string(), format!("{start_at:?}"));
                                             event.insert(apis::event::convention::EVENT_SERVICE.to_string(), api_impl.as_ref().service_name());
                                             event.insert(apis::event::convention::EVENT_STATUS_CODE.to_string(), resp.status().as_u16().to_string());
                                             event.insert(apis::event::convention::EVENT_ACTION.to_string(), "{{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}".to_string());
                                             event.insert(apis::event::convention::EVENT_LATENCY_SECS.to_string(), format!("{:.6}", chrono::Utc::now().signed_duration_since(start_at).as_seconds_f64()));
                                             api_impl.as_ref().dispatch(event).await;
                                        }
                                        {{/basicAnalytic}}

                                        resp.map_err(|e| { error!(error = ?e); StatusCode::INTERNAL_SERVER_ERROR })
}
